package com.ds.client.screen;


import java.rmi.RemoteException;
import java.util.ArrayList;
import org.lwjgl.util.vector.Vector3f;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.tiled.TileAtlas;
import com.badlogic.gdx.graphics.g2d.tiled.TileMapRenderer;
import com.badlogic.gdx.graphics.g2d.tiled.TiledLoader;
import com.badlogic.gdx.graphics.g2d.tiled.TiledMap;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;
import com.ds.client.actors.Car;
import com.ds.client.support.ServerStub;
import com.ds.server.RMIServerFramwork;
import com.ds.support.GameInfo;
import com.ds.support.GameStatus;

/**
 * race game screen, the main game screen
 */
public class RaceScreen implements Screen {

	InitGame game;
	private Stage stage;
	public RMIServerFramwork rService;
	private ArrayList<Car> carList;
	public static TiledMap map;
	TileAtlas atlas;
	TileMapRenderer render;
	Vector2 maxCamPosition = new Vector2(0, 0);
	public float width;
	public float height;
	private int action = 2;
	Button button;
	Music background;
	Music start;
	Music running;
	Music stopping;
	Car myself;
	OrthographicCamera cam;

	float[] hpList;
	float[] speedList;
	int[] loopList;
	Vector3f myPos;
	Image carStat;
	Image finishImage;
	long gamefinishTime = 0;
	ServerStub serverStub;

	public RaceScreen(InitGame initGame) {
		game = initGame;
	}

	@Override
	public void dispose() {
		try {
			serverStub.removeMyself(game.myID);
			stage.clear();
		} catch (RemoteException e) {
			game.setScreen(game.loseConnScreen);
		}
	}

	@Override
	public void hide() {

	}

	@Override
	public void pause() {

	}

	@Override
	public void render(float arg0) {
		try {
			renderProcess();
		} catch (RemoteException e) {

			game.setScreen(game.loseConnScreen);
		}
	}

	public void renderProcess() throws RemoteException {
		Gdx.gl.glClearColor(255, 255, 255, 255);
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		cam = (OrthographicCamera) stage.getCamera();

		myself = carList.get(game.myID);
		carRun(myself);
		game.gameInfo = serverStub.getGameInfo();
		speedList = game.gameInfo.getSpeedList();
		loopList = game.gameInfo.getLoopList();
		hpList = game.gameInfo.getHpList();

		// if car's hp is not empty
		if (myself.getCurrentHp() != hpList[game.myID] & hpList[game.myID] != 0) {
			Music collion, bird;
			collion = Gdx.audio.newMusic(Gdx.files
					.internal("res/music/tnt box explodes.wav"));
			collion.play();
			bird = Gdx.audio.newMusic(Gdx.files
					.internal("res/music/redbird.wav"));
			bird.play();
		}

		// up date car's hp
		myself.updatePos(game.gameInfo.getCarPos().get(game.myID));
		myself.setCurrentHp(hpList[game.myID]);

		// if car is running
		if (action == 1) {
			if (!running.isPlaying()) {
				running.play();
			}
		}

		// if car is braking
		if (action == 0) {
			if (running.isPlaying()) {
				running.pause();
			}
			if (!stopping.isPlaying() && speedList[game.myID] != 0f) {
				stopping.play();
			}
		}

		// if car is standing
		if (action == 2) {
			if (running.isPlaying()) {
				running.pause();
			}
			if (stopping.isPlaying()) {
				stopping.pause();
			}
		}

		if (speedList[game.myID] == 0f) {
			if (stopping.isPlaying()) {
				stopping.pause();
			}
		}

		// if car's hp is empty
		if (hpList[game.myID] == 0) {
			myself.moving = false;
			while (myself.getExplodeTime() > 0) {
				if (running.isPlaying()) {
					running.stop();
				}
				myself.setExplodeTime();
				Music bomb;
				bomb = Gdx.audio.newMusic(Gdx.files
						.internal("res/music/tnt box explodes.wav"));
				bomb.play();
				bomb.setLooping(false);
				bomb.setVolume(10f);
				Music end;
				end = Gdx.audio.newMusic(Gdx.files
						.internal("res/music/end.wav"));
				end.play();
				end.setLooping(false);
				end.setVolume(15);
				background.stop();
			}
		}

		// check others hp
		for (int i = 0; i < carList.size(); i++) {
			if (i != game.myID) {
				Car all = carList.get(i);
				all.updatePos(game.gameInfo.getCarPos().get(i));
				all.setCurrentHp(hpList[i]);
				if (hpList[i] == 0) {
					all.moving = false;
				}
			}

		}

		// update my car's position
		myPos = game.gameInfo.getCarPos().get(game.myID);
		// move cameras
		cameraMove(myPos);
		// update car status panel
		stage.removeActor(carStat);
		setImagePosition(carStat, stage.getCamera().position.x - 400, stage
				.getCamera().position.y - 300);
		stage.addActor(carStat);

		// update speed, laps labels information
		Label speed = (Label) stage.getRoot().findActor("speed");
		Label laps = (Label) stage.getRoot().findActor("laps");

		stage.removeActor(speed);
		stage.removeActor(laps);

		setLableStat(speed, game.gameInfo);
		setLableStat(laps, game.gameInfo);

		stage.addActor(speed);
		stage.addActor(laps);

		stage.act(Gdx.graphics.getDeltaTime());
		render.render(cam);

		// if game finish
		if (serverStub.getGameStatus(game.myID) == GameStatus.CLOSE) {
			int winnerID = serverStub.getWinner();
			// if current car is the winner
			if (winnerID != game.myID) {
				if (showFinishGame()) {
					dispose();
					game.setScreen(game.loseScreen);
				}
			}
			// if current is car is not the winner
			else {
				if (showFinishGame()) {
					dispose();
					game.setScreen(game.winScreen);
				}
			}
		}

		stage.draw();
	}

	@Override
	public void resize(int arg0, int arg1) {

	}

	@Override
	public void resume() {

	}

	@Override
	public void show() {
		stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),
				false);
		try {
			serverStub = new ServerStub();
			initRace();
		} catch (Exception e) {
			game.setScreen(game.loseConnScreen);
		}

	}

	public void initRace() throws RemoteException {
		background = Gdx.audio.newMusic(Gdx.files
				.internal("res/music/background.mp3"));
		start = Gdx.audio.newMusic(Gdx.files.internal("res/music/start.mp3"));
		running = Gdx.audio.newMusic(Gdx.files
				.internal("res/music/running.wav"));
		stopping = Gdx.audio.newMusic(Gdx.files
				.internal("res/music/stopping.mp3"));
		map = TiledLoader.createMap(Gdx.files.internal("res/map/map.tmx"));
		atlas = new TileAtlas(map, Gdx.files.internal("res/map/"));
		render = new TileMapRenderer(map, atlas, 10, 10);
		maxCamPosition.set(render.getMapWidthUnits(), render
				.getMapHeightUnits());
		width = Gdx.graphics.getWidth();
		height = Gdx.graphics.getHeight();
		carList = new ArrayList<Car>();

		// speed label
		LabelStyle labelStyle = new LabelStyle(new BitmapFont(), Color.BLACK);
		Label speedLabel = new Label("Speed:", labelStyle, "speed");
		speedLabel.y = 800;
		speedLabel.x = 10;
		stage.addActor(speedLabel);

		// laps label
		Label lapslabel = new Label("laps:", labelStyle, "laps");
		lapslabel.y = 800;
		lapslabel.x = 400;
		stage.addActor(lapslabel);
		game.gameInfo = serverStub.getGameInfo();
		carStat = new Image(new TextureAtlas("res/carStat/carStat.pack")
				.findRegion(game.gameInfo.getCarTypes()[game.myID] + ""));

		stage.addActor(carStat);

		game.gameInfo = serverStub.getGameInfo();
		int[] carTypes = game.gameInfo.getCarTypes();
		ArrayList<Vector3f> carPos = game.gameInfo.getCarPos();
		
		// add cars
		for (int i = 0; i < game.gameInfo.getCarPos().size(); i++) {
			Car aCar = Car.getCar(carTypes[i]);
			aCar.updatePos(carPos.get(i));
			carList.add(aCar);
			stage.addActor(aCar);
		}
		for (Car car : carList) {
			stage.addActor(car);
		}

		InputMultiplexer inputMultiplexer = new InputMultiplexer();
		inputMultiplexer.addProcessor(stage);
		Gdx.input.setInputProcessor(inputMultiplexer);
	}

	public void carRun(Car car) throws RemoteException {

		if (car.moving) {
			// if client press "LEFT"
			if (Gdx.input.isKeyPressed(Keys.LEFT)) {
				try {
					Thread.sleep(35);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				if (serverStub.getGameStatus(game.myID) == GameStatus.RUNING)
					serverStub.moveCar(game.myID, "left");
			}
			// if client press "RIGHT"
			else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
				try {
					Thread.sleep(35);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				if (serverStub.getGameStatus(game.myID) == GameStatus.RUNING)
					serverStub.moveCar(game.myID, "right");

			}
			// if client press "UP"
			else if (Gdx.input.isKeyPressed(Keys.UP)) {
				action = 1;
				if (serverStub.getGameStatus(game.myID) == GameStatus.RUNING)
					serverStub.moveCar(game.myID, "forward");
			}
			// if client press "DOWN"
			else if (Gdx.input.isKeyPressed(Keys.DOWN)) {
				action = 0;
				if (serverStub.getGameStatus(game.myID) == GameStatus.RUNING)
					serverStub.moveCar(game.myID, "back");
			}
			// if client didn't press any button
			else {
				action = 2;
				serverStub.moveCar(game.myID, "stand");
			}
		}
	}

	/**
	 * update camera position
	 * @param camMove
	 */
	public void cameraMove(Vector3f camMove) {
		Vector3 viewport = stage.getCamera().position.cpy();
		viewport = viewport.add(camMove.x, camMove.y, camMove.z);
		Vector3 zbound = new Vector3(width / 2, height / 2, 0).add(viewport);
		stage.getCamera().position.set(camMove.x, camMove.y, 0);
	}

	/**
	 * init the camera position, which should be the same position with current
	 * car
	 * 
	 * @param car
	 */
	public void initCamPos(Car car) {
		stage.getCamera().position.x = car.getX();
		stage.getCamera().position.y = car.getY() + 130f;
	}

	/**
	 * update label position and message
	 * @param label
	 * @param gameInfo
	 */
	public void setLableStat(Label label, GameInfo gameInfo) {
		if (label.name == "speed") {
			label.x = stage.getCamera().position.x - 30;
			label.y = stage.getCamera().position.y - 278;
			label.setText(gameInfo.getSpeedList()[game.myID] * 10 + "km/h");
		} else {
			label.x = stage.getCamera().position.x + 120;
			label.y = stage.getCamera().position.y - 278;
			label.setText(gameInfo.getLoopList()[game.myID] + "/3");

		}

	}

	public static String[] splitSentence(String sentence) {
		String[] tokens = sentence.split(" ");
		return tokens;
	}

	public void setImagePosition(Image image, float x, float y) {
		image.x = x;
		image.y = y;
	}

	/**
	 * 
	 * @return
	 */
	public boolean showFinishGame() {
		if (gamefinishTime == 0) {
			gamefinishTime = System.nanoTime() / 1000000000;
			finishImage = new Image(new TextureAtlas(
					"res/resultScreen/finish.pack").findRegion("finish"));
			setImagePosition(finishImage, stage.getCamera().position.x - 400,
					stage.getCamera().position.y - 300);
			stage.addActor(finishImage);
		} else {
			return (System.nanoTime() / 1000000000 - gamefinishTime >= 3);
		}
		return false;

	}

}
